package com.zou;

import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.locks.InterProcessMutex;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.data.Stat;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;

public class ZkCuratorLock implements Lock {

	private static final String LOCK_PATH="/LOCK";

	private static final String ZOOKEEPER_IP_PORT ="localhost:2181"; //192.168.149.135:2181

	// InterProcessSemaphoreMutex：分布式排它锁（非可重入锁）
	// InterProcessReadWriteLock：分布式读写锁
	// InterProcessMultiLock：将多个锁作为单个实体管理的容器
	// InterProcessSemaphoreV2：共享信号量
	// InterProcessMutex：分布式可重入排它锁
	private InterProcessMutex lock ;

	//客户端连接对象
	private CuratorFramework client;


	//判断有没有LOCK目录，没有则创建
	public ZkCuratorLock() {
		//重试策略
		RetryPolicy retryPolicy = new ExponentialBackoffRetry(3000, 10);
		client = CuratorFrameworkFactory.builder()
				.connectString(ZOOKEEPER_IP_PORT)
				.sessionTimeoutMs(60 * 1000)
				.connectionTimeoutMs(15 * 1000)
				.retryPolicy(retryPolicy)
				.build();
		//开启连接
		client.start();

		try {
			//判断节点是否存在
			Stat stat = client.checkExists().forPath(LOCK_PATH);
			if (stat == null){
				//节点不存在，创建永久节点
				client.create().withMode(CreateMode.PERSISTENT).forPath(LOCK_PATH);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		//创建分布式可重入排它锁
		lock = new InterProcessMutex(client, LOCK_PATH);

	}

	/**
	 * 加锁
	 */
	@Override
	public void lock() {
		if(tryLock()){
			//获得 Zk 分布式锁!
			return;
		}
		//没有获取到继续尝试获取
		lock();
	}

	/**
	 * 尝试加锁
	 * @return
	 */
	@Override
	public boolean tryLock() {
		try {
			return lock.acquire(3, TimeUnit.SECONDS);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return false;
	}

	/**
	 * 释放锁
	 */
	@Override
	public void unlock() {
		//删除当前临时节点
		//释放锁
		try {
			lock.release();
			System.out.println("---------------------------->" + Thread.currentThread().getName()+" 加锁/释放锁!");
		} catch (Exception e) {
			e.printStackTrace();
		}

	}
	
	//==========================================如下方法无需实现
	@Override
	public void lockInterruptibly() throws InterruptedException {
		// TODO Auto-generated method stub

	}

	@Override
	public boolean tryLock(long time, TimeUnit unit)
			throws InterruptedException {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public Condition newCondition() {
		// TODO Auto-generated method stub
		return null;
	}

}
